#ifndef _TreeNode_h_
#define _TreeNode_h_

#include "ResourceMgr.h"
#include "GameComponent.h"
#include "MenuScreen.h"
#include <ctype.h>
#include <iostream>
#include <string>
using namespace std;

class TreeNode;

class TreeNode {
	public:
		TreeNode (const string& text, int nchildren=0, TreeNode* parent=NULL) {
			parent_    = parent;
			if (parent != NULL) {
				parent->addChild(this);
			}
			nchildren_ = nchildren;
			index_ = -1;
			selectedIndex_ = 0;
			if (nchildren > 0) {
				children_  = new TreeNode*[nchildren];
			}
			else {
				children_ = NULL;
			}
			
			text_ = string(text);
			// Further improvements: use a string manager for
			// translations
			// text = string(StringMgr::translate(text));

			// Convert string to upper case
			for (int k = 0; k < text_.length(); k++) {
				text_[k] = toupper(text_[k]);
			}

			selected_ = NULL;
			createTextSurfaces_();
		}
		// Recursive deletion
		~TreeNode () {
			for (int k=0; k < nchildren_; k++) {
				if (children_[k] != NULL) {
					delete children_[k];
					children_[k] = NULL;
				}
			}
			if (children_ != NULL) {
				delete children_;
				children_ = NULL;
			}
			nchildren_ = 0;
			index_     = -1;
			parent_    = NULL;
			text_      = string("");
			selected_  = NULL;		
			selectedIndex_ = 0;
			SDL_FreeSurface(textSurface_);
			SDL_FreeSurface(textMask_);
			textSurface_ = NULL;
			textMask_ = NULL;
		}
		void setChild (TreeNode *child, int n) {
			children_[n] = child;
		}
		void addChild (TreeNode *child) {
			children_[++index_] = child;
		}
		TreeNode *getChild (int n) {
			return children_[n];
		}
		TreeNode **getChildren (int& size) {
			size = nchildren_;
			return children_;
		}
		int getNChildren () {
			return nchildren_;
		}
		TreeNode *getParent () {
			return parent_;
		}
		//string& getText () {
		const char *getText () {
			return text_.c_str();
		}
		bool hasChildren () {
			return nchildren_ > 0;
		}
		bool hasParent () {
			return parent_ != NULL;
		}

		virtual void setSelected (TreeNode *child) {
			selected_ = child;
			for (int k=0; k < nchildren_; k++) {
				if (children_[k] == child) {
					selectedIndex_ = k;
					child->selected();
					break;
				}
			}
		}
		TreeNode *getSelected () {
			return selected_;
		}
		int getSelectedIndex () {
			return selectedIndex_;
		}
		virtual void selected () {
			cout << "Item selected: " << getText() << endl;
		}
	

		void blitMask ();
		void blitText ();

	private:
		void createTextSurfaces_ ();

	protected:
		string 		 text_;
		TreeNode **children_;
		TreeNode  *parent_;
		TreeNode  *selected_;
		int			nchildren_;
		int			index_;
		int			selectedIndex_;
		SDL_Surface *textSurface_;
		SDL_Surface *textMask_;
		SDL_Rect	srcRect_;
		SDL_Rect	dstRect_;
};

// A TreeNode with 2 possible children: "ON" or "OFF"
class BoolTreeNode : public TreeNode {
	public:
		BoolTreeNode (const string& text, TreeNode *parent, bool& value)
			: TreeNode(text, 2, parent), value_(value) {
			setChild(new TreeNode("ON",  0, this), 0);
			setChild(new TreeNode("OFF", 0, this), 1);
			// Initial selection
			if (value) {
				selectedIndex_ = 0;
				selected_ = children_[selectedIndex_];
			}
			else {
				selectedIndex_ = 1;
				selected_ = children_[selectedIndex_];
			}
		}

		virtual void setSelected (TreeNode *child) {
			TreeNode::setSelected(child);
			if (child == children_[0]) {
				value_ = true;
			}
			else if (child == children_[1]) {
				value_ = false;
			}
		}

	private:
		bool& value_;
};

// A TreeNode holding a list of string choices
class StringTreeNode : public TreeNode {
	public:
		StringTreeNode (const string& text, int argc, const char** argv, TreeNode *parent, const char** value)
			: TreeNode(text, argc, parent) {
			for (int k=0; k < argc; k++) {
				setChild(new TreeNode(string(argv[k]), 0, this), k);
				// "value" may not be initialized yet ! (NULL)
				value_ = value;
				if (!strcmp(*value, argv[k])) {
					selectedIndex_ = k;
					selected_ = children_[selectedIndex_];
				}
			}
		}

		virtual void setSelected (TreeNode *child) {
			TreeNode::setSelected(child);
			//value_ = (char *)child->getText().c_str();
			*value_ = (char *)child->getText();
		}

	private:
		const char **value_;
};

// A TreeNode which starts a game component when selected
class CommandTreeNode : public TreeNode {
	public:
		CommandTreeNode (const string& text, TreeNode *parent, GameComponent *command)
			: TreeNode(text, 0, parent) {
			component_ = command;
		}

		virtual void selected () {
			TreeNode::selected();
			MenuScreen::instance()->stop();
			component_ -> start();
		}

	private:
		GameComponent *component_;
};

#endif

